// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`timescale 1 ns / 1 ps

module espi_pc_io_short_fsm
  #(
    parameter HEADER_BYTES = 4,
    parameter DATA_BYTES = 4
    )
    (
     // Command Decode
     input logic         detect_iord_short,
     input logic         detect_iowr_short,
     input logic         detect_short_1b,
     input logic         detect_short_2b,
     input logic         detect_short_4b,
    
     // Rx Shifter
     input logic         rx_detect_crc_end,
     input [7:0]         header_byte[HEADER_BYTES],
     input [7:0]         data_byte[DATA_BYTES],
     input logic         stop_det,

     // Error Detection
     input logic         pc_error_condition,
    
     // Avalon Memory-Mapped I/O Master
     output logic [15:0] io_address,
     output logic        io_write,
     output logic [7:0]  io_writedata,
     output logic        io_read,
     input logic [7:0]   io_readdata,
     input logic         io_waitrequest,

     // Tx Shifter
     output logic [31:0] pc_io_data,
     output logic        pc_io_data_valid,
    
     input logic         clk,
     input logic         channel_reset_n
     );

    logic [2:0] io_idx;
    logic [2:0] io_bytes;

    always @(posedge clk or negedge channel_reset_n) begin
        if (!channel_reset_n) begin
            io_address       <= 0;
            io_write         <= 0;
            io_writedata     <= 0;
            io_read          <= 0;
            io_idx           <= 0;
            io_bytes         <= 0;
            pc_io_data       <= 0;
            pc_io_data_valid <= 0;
        end
        else begin
            if (!io_waitrequest) begin
                if ((io_read || io_write) && io_idx < io_bytes) begin
                    io_address   <= io_address + 1'd1;
                    io_writedata <= data_byte[io_idx];
                    io_idx       <= io_idx + (io_write | io_read);
                end
                else if (rx_detect_crc_end && !pc_error_condition) begin
                    // The command phase completed successfully, start the operation
                    io_address   <= {header_byte[0], header_byte[1]};
                    io_idx       <= 3'd1;
                    io_bytes     <= {detect_short_4b, detect_short_2b, detect_short_1b};
                    io_read      <= detect_iord_short;
                    io_write     <= detect_iowr_short;
                    io_writedata <= data_byte[0];
                end
                else begin
                    io_read  <= 0;
                    io_write <= 0;
                end // else: !if(rx_detect_crc_end_1 && !pc_error_condition)

                if (io_read) begin
                    pc_io_data[(io_idx-1)*8+:8] <= io_readdata;
                end

                if (io_read || io_write) begin
                    pc_io_data_valid <= io_idx == io_bytes;
                end
            end // if (!io_waitrequest)

            if (stop_det) begin
                pc_io_data       <= 0;
                pc_io_data_valid <= 0;
            end
        end // else: !if(!channel_reset_n)
    end // always @ (posedge clk or negedge channel_reset_n)

endmodule // espi_pc_io_short_fsm
